﻿Imports System.IO
Imports System.Xml
Imports System.Xml.Serialization

#Region "Application settings"

''' <summary>
''' The application settings class
''' </summary>
''' <remarks></remarks>
Friend Class AppSettings

    ''' <summary>
    ''' Indicates if there was any error while saving or retrieving settings
    ''' </summary>
    ''' <value>Default is False</value>
    ''' <returns>True if there was any error while saving or retrieving settings; otherwise false</returns>
    ''' <remarks></remarks>
    Shared Property ErrorDetected() As Boolean = False

    ''' <summary>
    ''' Gets or sets a value indicating whether the application should scan for installed apps at startup
    ''' </summary>
    ''' <returns>True if the application should scan for installed apps at startup; otherwise false</returns>
    ''' <remarks>Feature only available if OS is Windows 8 or higher</remarks>
    Shared Property ScanInstalledAppsAtStartup() As Boolean
        Get
            Try
                Return ReadSettings("ScanInstalledAppsAtStartup")
            Catch ex As Exception
                ErrorDetected = True

                Return False
            End Try
        End Get
        Set(ByVal value As Boolean)
            Try
                WriteSettings("ScanInstalledAppsAtStartup", value.ToString)
            Catch ex As Exception
                ErrorDetected = True
            End Try
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets a value indicating what kind of cancellation should the application do
    ''' </summary>
    ''' <value>0 = Normal deletion; 1 = Gutmman Secure Deletion</value>
    ''' <returns>0 if normal deletion is selected; 1 if Gutmann Secure Deletion is selected</returns>
    ''' <remarks></remarks>
    Shared Property OverwriteType() As Integer
        Get
            Try
                Return CType(ReadSettings("OverwriteType"), Integer)
            Catch ex As Exception
                ErrorDetected = True

                Return 1
            End Try
        End Get
        Set(ByVal value As Integer)
            Try
                WriteSettings("OverwriteType", value.ToString)
            Catch ex As Exception
                ErrorDetected = True
            End Try
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets a value indicating whether the application should permanently delete files or
    ''' send them to the Reclycle Bin
    ''' </summary>
    ''' <value>0 = Permanently delete files; 1 = Send files to the Reclycle Bin</value>
    ''' <returns>0 if the application should permanently delete files; otherwise 1</returns>
    ''' <remarks></remarks>
    Shared Property OverwriteMethod() As Integer
        Get
            Try
                Return CType(ReadSettings("OverwriteMethod"), Integer)
            Catch ex As Exception
                ErrorDetected = True

                Return 0
            End Try
        End Get
        Set(ByVal value As Integer)
            Try
                WriteSettings("OverwriteMethod", value.ToString)
            Catch ex As Exception
                ErrorDetected = True
            End Try
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets a value indicating whether the application should prompt the user to confirm a folder removal
    ''' </summary>
    ''' <returns>True if the application should prompt the user to confirm a folder removal; otherwise false</returns>
    ''' <remarks></remarks>
    Shared Property ConfirmWhenDeletingFolder() As Boolean
        Get
            Try
                Return CType(ReadSettings("ConfirmWhenDeletingFolder"), Boolean)
            Catch ex As Exception
                ErrorDetected = True

                Return False
            End Try
        End Get
        Set(ByVal value As Boolean)
            Try
                WriteSettings("ConfirmWhenDeletingFolder", value.ToString)
            Catch ex As Exception
                ErrorDetected = True
            End Try
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets a value indicating whether the application should prompt a confirmation message before running the cleaner
    ''' </summary>
    ''' <returns>True if the application should prompt a confirmation message before running the cleaner; otherwise false</returns>
    ''' <remarks></remarks>
    Shared Property ConfirmBeforeRunningCleaner() As Boolean
        Get
            Try
                Return CType(ReadSettings("ConfirmBeforeRunningCleaner"), Boolean)
            Catch ex As Exception
                ErrorDetected = True

                Return False
            End Try
        End Get
        Set(ByVal value As Boolean)
            Try
                WriteSettings("ConfirmBeforeRunningCleaner", value.ToString)
            Catch ex As Exception
                ErrorDetected = True
            End Try
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets a value indicating whether the application should refresh the folders sizes before running the cleaner
    ''' </summary>
    ''' <returns>True if the application should refresh the folders sizes before running the cleaner; otherwise false</returns>
    ''' <remarks></remarks>
    Shared Property RefreshSizeBeforeRunningCleaner() As Boolean
        Get
            Try
                Return CType(ReadSettings("RefreshSizeBeforeRunningCleaner"), Boolean)
            Catch ex As Exception
                ErrorDetected = True

                Return True
            End Try
        End Get
        Set(ByVal value As Boolean)
            Try
                WriteSettings("RefreshSizeBeforeRunningCleaner", value.ToString)
            Catch ex As Exception
                ErrorDetected = True
            End Try
        End Set
    End Property

End Class

#End Region

#Region "XML settings handler"

''' <summary>
''' The XML settings handler
''' </summary>
''' <remarks></remarks>
Friend Module SettingsHandler

    ''' <summary>
    ''' Write a value to the XML settings file
    ''' </summary>
    ''' <param name="node">The XML node in which the value will be writeen</param>
    ''' <param name="value">The value to write</param>
    ''' <remarks></remarks>
    Friend Sub WriteSettings(node As String, value As String)
        ' Declare a new XmlDocument that will be used to hold XML settings
        Dim xmlDoc As New XmlDocument()

        Try
            ' Open the XML settings file
            xmlDoc.Load(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & _
                                                "\Modern UI Apps Cleaner\config.dat")

            ' Get where to save the value
            Dim element As XmlElement = xmlDoc.SelectSingleNode("Configuration/" & node)

            ' Write the value to the XML file
            If Not element Is Nothing Then
                element.InnerText = value
            End If

            ' Save the XML settings file
            xmlDoc.Save(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & _
                                                "\Modern UI Apps Cleaner\config.dat")
        Catch ex As Exception
            ' If any other exception occurred, show an error message
            If ex.InnerException IsNot Nothing Then
                MessageBox.Show("Error while saving settings: " & ex.Message + ControlChars.CrLf + ControlChars.CrLf + _
                                ex.InnerException.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            Else
                MessageBox.Show("Error while saving settings: " & ex.Message, _
                                "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End If
        Finally
            ' Clear the XmlDocument reference
            If xmlDoc IsNot Nothing Then
                xmlDoc = Nothing
            End If
        End Try
    End Sub

    ''' <summary>
    ''' Read a value from the XML settings file
    ''' </summary>
    ''' <param name="node">The XML node that holds the value to be read</param>
    ''' <exception cref="ArgumentNullException">Thrown if the argument is null</exception>
    ''' <exception cref="ArgumentException">Thrown if the argument provided is not valid</exception>
    ''' <exception cref="FileNotFoundException">Thrown if the XML settings file doesn't exist</exception>
    ''' <exception cref="PathTooLongException">Thrown if the XML settings file path exceeds the system-maximum</exception>
    ''' <exception cref="IOException">Thrown if an I/O error occurs</exception>
    ''' <exception cref="NotSupportedException">Thrown if the filename is in an invalid format.</exception>
    ''' <exception cref="OutOfMemoryException">Thrown if there's no enough memory to continue the operation</exception>
    ''' <exception cref="Security.SecurityException">Thrown if the caller doesn't have the required permissions</exception>
    ''' <exception cref="UnauthorizedAccessException">Thrown if: 1. Filename specified a file that is read-only;
    ''' 2. This operation is not supported on the current platform; 3. Filename specified a directory; 4. The caller does not have the required permission.</exception>
    ''' <returns>The value hold by the XML node as String</returns>
    ''' <remarks></remarks>
    Friend Function ReadSettings(node As String) As String
        ' Assign a value to the function
        ReadSettings = Nothing

        ' Declare a new XmlDocument that will be used to hold XML settings
        Dim xmlDoc As New XmlDocument()

        Try
            ' Open the XML settings file
            xmlDoc.Load(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & _
                                                "\Modern UI Apps Cleaner\config.dat")

            ' Get where to read the value
            Dim element As XmlElement = xmlDoc.SelectSingleNode("Configuration/" & node)

            ' Read the value
            If Not element Is Nothing Then
                ReadSettings = element.InnerText
            End If

            ' If the element couldn't be found, throw an exception
            If ReadSettings Is Nothing Then
                Throw New NullReferenceException("Cannot find the XML node that contains the value")
            End If

            Return ReadSettings
        Catch an As ArgumentNullException
            Return "arg null ex"
        Catch a As ArgumentException
            Return "arg ex"
        Catch fnf As FileNotFoundException
            Return "file not found ex"
        Catch ptl As PathTooLongException
            Return "path too long ex"
        Catch io As IOException
            Return "file in use ex"
        Catch ns As NotSupportedException
            Return "path is in invalid format ex"
        Catch oom As OutOfMemoryException
            Return "not enough memory ex"
        Catch s As Security.SecurityException
            Return "user permissions ex"
        Catch ua As UnauthorizedAccessException
            Return "unauthorized access ex"
        Catch ex As Exception
            ' If any other exception occurred, show an error message and return nothing
            If ex.InnerException IsNot Nothing Then
                MessageBox.Show("Error while reading settings: " & ex.Message + ControlChars.CrLf + ControlChars.CrLf + _
                                ex.InnerException.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            Else
                MessageBox.Show("Error while reading settings: " & ex.Message, _
                                "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End If

            Return String.Empty
        Finally
            ' Clear the XmlDocument reference
            If xmlDoc IsNot Nothing Then
                xmlDoc = Nothing
            End If
        End Try
    End Function

    ''' <summary>
    ''' Asyncronously check if the passed file is a valid XML settings file for the application
    ''' </summary>
    ''' <returns>True if the file is a valid XML settings file for the application; otherwise false</returns>
    ''' <remarks></remarks>
    Public Async Function CheckIfValidSettings() As Task(Of Boolean)
        ' Create a new boolean value that will hold the result of our operation
        Dim result As Boolean

        ' Initialize a new XmlTextReader from the XML settings file location
        Using reader As New XmlTextReader(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & _
                                                "\Modern UI Apps Cleaner\config.dat")
            Try
                ' Assign to the boolean its value asyncronously
                result = Await Task.Run(Function()
                                            ' Start reading the file
                                            While reader.Read()
                                                ' If the file doesn't have all the required xml elements, return false,
                                                ' stop reading and exit the function
                                                If reader.IsStartElement() AndAlso Not reader.Name = "Configuration" AndAlso _
                                                    Not reader.Name = "ScanInstalledAppsAtStartup" AndAlso _
                                                    Not reader.Name = "OverwriteType" AndAlso _
                                                    Not reader.Name = "OverwriteMethod" AndAlso _
                                                    Not reader.Name = "ConfirmWhenDeletingFolder" AndAlso _
                                                    Not reader.Name = "ConfirmBeforeRunningCleaner" AndAlso _
                                                    Not reader.Name = "RefreshSizeBeforeRunningCleaner" Then

                                                    Return False
                                                    Exit Function
                                                End If
                                            End While

                                            ' If the reading was completed successfully, it means that the file is valid
                                            ' So return true
                                            Return True
                                        End Function)
            Catch ex As Exception
                ' If any exception occurred, return false
                result = False
            End Try
        End Using
        ' End XmlTextReader

        Return result
    End Function
End Module

#End Region

